package com.atomos.utils
{
	import flash.geom.Point;
	
	import com.bourre.structures.Dimension;	
	
	/**
	 * An utility class which offer many convenient methods 
	 * to perform commonly used mathematical operations.
	 * 
	 * @author	Cédric Néhémie
	 */
	public class MathUtils
	{
		/*
		 * GEOMETRIC METHODS 
		 */
		/**
		 * Pre-computed value of PI * 2.
		 */
		static public const PI2 : Number = Math.PI * 2;
		
		/**
		 * Converts an angle in degrees to an angle in radians.
		 * 
		 * @param	a	an angle in degrees.
		 * @return 	an angle in radians. 
		 */
		static public function deg2rad ( a : Number ) : Number
		{
			return a * Math.PI / 180;
		}
		
		/**
		 * Converts an angle in radians to an angle in degrees.
		 * 
		 * @param	a	an angle in radians.
		 * @return	an angle in degrees. 
		 */
		static public function rad2deg ( a : Number ) : Number
		{
			return a * 180 / Math.PI;
		}
		
		/**
		 * 
		 * @param	i
		 * @param	gridSize
		 * @return
		 */
		static public function id2pos( i : Number, gridSize : Dimension ) : Point
		{
			var sx:Number = gridSize.width;
			var x:Number = i % sx;
			var y:Number = ( i - x ) / sx;
			return new Point( x, y );
		}	
		/**
		 * 
		 * @param	p
		 * @param	gridSize
		 * @return
		 */
		static public function pos2id( p : Point, gridSize : Dimension ) : Number
		{		
			var sx:Number = gridSize.width;
			return p.y * sx + p.x;
		}		
		/**
		 * 
		 * @param	x
		 * @param	y
		 * @param	gridSize
		 * @return	
		 */
		static public function pos2idXY ( x : Number, y : Number, gridSize : Dimension ) : Number
		{		
			var sx:Number = gridSize.width;
			return y * sx + x;
		}
		
		/*
		 * ARITHMETIC METHODS 
		 */
		/**
		 * Returns a float in the range <code>0 - 1</code> according
		 * to the relative position of <code>value</code> in the
		 * range <code>minimum - maximum</code>.
		 * 
		 * @param	value	
		 * @param	minimum	
		 * @param	maximum	
		 * @return	
		 */
		static public function normalize( value : Number, 
										  minimum : Number, 
										  maximum : Number) : Number
        {
            return (value - minimum) / (maximum - minimum);
        }     
		/**
		 * Returns the result of the interpolation of a normalized value
		 * <code>normValue</code> in the range <code>minimum - maximum</code>.
		 * 
		 * @param	normValue
		 * @param	minimum
		 * @param	maximum
		 * @return
		 */
        static public function interpolate( normValue : Number, 
        									minimum : Number, 
        									maximum : Number) : Number
        {
            return minimum + (maximum - minimum) * normValue;
        }    
		/**
		 * Returns a value in the range <code>min2 - max2</code>
		 * corresponding to the place of <code>value</code> in the
		 * range <code>min1 - max1</code>.
		 * 
		 * @param	value
		 * @param	min1
		 * @param	max1
		 * @param	min2
		 * @param	max2
		 * @return	
		 */
        static public function map( value : Number, 
        							min1 : Number, 
        							max1 : Number, 
        							min2 : Number, 
        							max2 : Number ) : Number
        {
            return interpolate( normalize(value, min1, max1), min2, max2);
        }      	
        /**
         * Return either <code>minimum</code> or <code>maximum</code>
         * according to which boudary is the nearest to the position
         * of <code>value</code> in that range. For example, for a range
         * of <code>0 - 1</code>, passing <code>0.4</code> to the method
         * will return <code>0/code>, at the opposite, passing 
         * <code>0.6</code> will return <code>1</code>.
         * 
         * @param	value
         * @param	minimum
         * @param	maximum
         * @return	
         */
        static public function clamp ( value : Number, 
        							   minimum : Number, 
        							   maximum : Number ) : Number
        {
        	return (value - minimum > maximum - value ) ? maximum : minimum ;
		}
	}
}